//
// Created by denglibin on 19-10-28.
//
#include<sys/socket.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>
#include <errno.h>
#include<fcntl.h>
#include "wrap.h"

#define  MAX_LINE  4096
#define  SERVER_PORT 8888
#define  OPEN_MAX  10240
/**
 *设置为非阻塞
 **/
static int  setnonblocking(int sockFd){
    if(fcntl(sockFd, F_SETFL, fcntl(sockFd, F_GETFD,0)|O_NONBLOCK) == -1){
        return -1;
    }
    return 0;
}

static void start_server(){
    int server_fd, conn_fd, epoll_fd, n_ready, i, sock_fd,n;
    struct sockaddr_in client_addr, servaddr;
    char str[MAX_LINE];
    socklen_t  client_addr_len = sizeof(client_addr);
    server_fd = Socket(AF_INET, SOCK_STREAM, 0);
    //声明 epoll_event结构体的变量，ev 用于注册事件，数组用于回传要处理的事件
    struct epoll_event ev, events[OPEN_MAX];

    // 把socket设置为非阻塞模式
     setnonblocking(server_fd);
    //编辑地址信息
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERVER_PORT);

    Bind(server_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    /*默认最大128*/
    Listen(server_fd, 20);

    //创建epoll句柄
    epoll_fd = epoll_create(OPEN_MAX);
    if(epoll_fd == -1){
        perror("epoll_create:");
        exit(-1);
    }
    ev.events = EPOLLIN;
    ev.data.fd = server_fd;

    //注册epoll事件
    if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1){
        perror("epoll_ctl:serverFd");
        exit(-1);
    }
    for(;;){
        printf("epoll_wait\n");
        n_ready = epoll_wait(epoll_fd, events, OPEN_MAX, -1); // -1:永久阻塞
        if(n_ready == -1){
            perror("epoll_wait:");
            exit(-1);
        }
        for(i = 0; i < n_ready; i++){
            if(!(events[i].events & EPOLLIN)){
                continue;
            }
            if(events[i].data.fd == server_fd){ // 新的连接
                conn_fd = Accept(server_fd, (struct sockaddr *)& client_addr, &client_addr_len);
                bzero(str, MAX_LINE);
                printf("new connection %s:%d\n",
                       inet_ntop(AF_INET, &client_addr.sin_addr, str, sizeof(str)),
                       ntohs(client_addr.sin_port));
                ev.events = EPOLLIN;
                ev.data.fd = conn_fd;
                setnonblocking(conn_fd);
                //新的客户端 注册epoll事件
                if(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev) == -1){
                    perror("epoll_ctl:conn_fd:");
                    exit(-1);
                }
            } else { //客户端数据可读
                sock_fd = events[i].data.fd;
                bzero(str, MAX_LINE);
                n = recv(sock_fd, str, MAX_LINE, 0);
                if(n < 0){
                    perror("recv:");
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, NULL);
                    Close(sock_fd);
                } else if(n == 0){
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, NULL);
                    Close(sock_fd);
                    printf("%d client disconnect\n", sock_fd);
                } else {
                    int j;
                    for(j = 0; j < n; j++){
                        str[j] = (char)toupper((int)str[j]);
                    }
                    send(sock_fd, str, n, 0);
                }
             /*   while ((n = read(conn_fd, str, MAX_LINE)) >0){ //设置为非阻塞可以采用循环读取 直到读完 (n<0)
                    printf("%s\n", str);
                }*/
            }
        }
    }
}

static int main_(void){

    start_server();
    return 0;
}
